package moving

import (
	"src/zeus/linmath"
	"src/zeus/logger"
	"src/zeus/pathfinder"
)

// 移动模块
type MoveMgr struct {
	pathfinder.IPathFinder
	user IUser

	Paths []linmath.Vector3

	//设置次数
	numSet int

	//是否已激活（只要跑过Update都算激活了）
	IsActive bool
	// 是否在跑
	isRuning bool
}

func NewMoveMgr(finder pathfinder.IPathFinder, user IUser) (result *MoveMgr) {
	result = new(MoveMgr)
	result.IPathFinder = finder
	result.user = user
	result.Paths = nil
	result.numSet = 0
	return
}

func (this *MoveMgr) Update(deltatime float32) bool {
	if !this.IsActive {
		this.IsActive = true
	}

	if !this.IsMoving() {
		return false
	}

	speed := this.user.GetMovSpeed()
	movedistance := deltatime * speed
	maxLen := int32(len(this.Paths))
	var targetpos linmath.Vector3
	var dota int32
	pos := this.user.GetMovPos()
	currentStep := this.user.GetMovCurrIndex()
	for {
		//当前目标路点
		targetpos = this.Paths[currentStep]
		//距离朝向
		dotapos := targetpos.Sub(pos)
		//朝向
		dota = int32(linmath.VectorToAngle(dotapos))

		if dotapos.IsOutOfRange(movedistance) {
			//到下个节点距离比移动时间的距离长
			dotapos.Normalize()
			pos.AddS(dotapos.Mul(movedistance))
			break

		} else {
			currentStep++
			if currentStep >= maxLen {
				movedistance = dotapos.Len()
				pos = targetpos
				this.user.SetMovCurrIndexNoDirty(currentStep)
				this.user.SetMovPos(pos)
				this.user.SetMovRota(dota)
				this.Stop()

				return true
			} else {
				//减掉这个点的距离
				movedistance -= dotapos.Len()
				pos = targetpos
				this.user.SetMovCurrIndexNoDirty(currentStep)
			}
		}
	}
	if this.numSet > 5 {
		this.numSet = 0
		this.user.SetMovPos(pos)
		this.user.SetMovRota(dota)
	} else {
		this.numSet++
		this.user.SetMovPosNoDirty(pos)
		this.user.SetMovRotaNoDirty(dota)
	}
	return true
}

// 是否在移动
func (this *MoveMgr) IsMoving() bool {
	return this.isRuning
	// if this.Paths != nil && this.user.GetMovCurrIndex() < int32(len(this.Paths)) {
	// 	return true
	// }
	// return false
}

func (this *MoveMgr) TurnToRota(rota int32) {
	if this.user.CanRota() {
		this.user.SetMovRota(rota)
	}
}

func (this *MoveMgr) MoveToPos(targetpos linmath.Vector3) bool {
	sPos := this.user.GetMovPos()
	if sPos.IsEqualXZ(targetpos) {
		logger.Debug(logger.LogKey_MoveSys, "[MoveMgr] MoveToPos 已经到达位置")
		if this.IsMoving() {
			this.Stop()
		}
		return true
	}
	if !this.user.CanMove() {
		return false
	}
	path, ok := this.FindPath(sPos, targetpos)
	if !ok {
		// logger.Warnf("MoveToPos Has not find path!%s mypos:%s tarpos:%s", this.user, sPos, targetpos)

		//加个寻路容错，如果自己当前点是不可达点，做位置强同步修正
		if tarPos, ok := this.GetNear(&sPos); ok {
			if !sPos.IsEqualXZ(*tarPos) {
				this.user.ForcePosNotice(*tarPos)
				return false
			} else if tarPos, ok := this.RaycastEx(sPos, targetpos); ok {
				//起点合法，那目标点一定不合法，就走一下射线检查
				targetpos = *tarPos
				path, _ = this.FindPath(sPos, targetpos)
			}
			// } else if tarPos, ok := this.GetNear(&targetpos); ok {
			// 	this.user.ForcePosNotice(*tarPos)
		} else {
			logger.Warnf("MoveToPos Failed allpos invaild.pos:%v user:%s", sPos, this.user)
		}

		// logger.Debugf(logger.LogKey_MoveSys, "MoveToPos Has not find path!%s mypos:%s tarpos:%s ", this.user, this.user.GetMovPos(), targetpos)
	}
	lenPath := len(path)
	if lenPath <= 0 {
		return false
	}
	if lenPath == 1 {
		if path[0].IsEqualXZ(sPos) {
			// 试图寻路，却发现无法起步
			return false
		}
	}
	this.Start(path[1:], nil)
	return true
}

// 飞过去
func (this *MoveMgr) MoveToPosByFly(targetpos linmath.Vector3) bool {
	sPos := this.user.GetMovPos()
	if sPos.IsEqualXZ(targetpos) {
		logger.Debug(logger.LogKey_MoveSys, "[MoveMgr] MoveToPos 已经到达位置")
		this.Stop()
		return true
	}
	if !this.user.CanMove() {
		return false
	}
	path := []linmath.Vector3{
		targetpos,
	}
	this.Start(path, nil)
	return true
}

func (this *MoveMgr) Start(paths []linmath.Vector3, call MoveCallBack) {
	if paths == nil || len(paths) == 0 {
		return
	}
	if !this.user.CanMove() {
		return
	}
	this.Paths = paths
	this.user.SetMovCurrIndex(0)
	this.user.BroadcastTargetPosByAOI(paths)
	this.numSet = 0
	this.user.SetMovPosDirty()
	this.user.SetMovRotDirty()

	//通知寻路开始
	this.user.NoticeStart()
	this.isRuning = true
}

func (this *MoveMgr) Stop() {
	if !this.isRuning {
		return
	}
	//通知寻路结束
	this.user.NoticeStop()
	// if !this.IsMoving() {
	// 	//如果没移动，就不赋值了
	// 	return
	// }

	this.Paths = nil
	this.user.SetMovCurrIndex(-1)
	this.user.BroadcastTargetPosByAOI(nil)
	this.user.SetMovPosDirty()
	this.user.SetMovRotDirty()
	this.isRuning = false
	logger.Debug(logger.LogKey_MoveSys, " 移动停止")

}
